//Constants
var DIFFICULTY = "Hard";
var EXPLORE_MODE = false;
var FRAMETIME = 30;

//Sprites and graphics
var playerSprite = "images/Player.png";
var player2Sprite = "images/player2.png";
var bossSprite = "images/Boss01.png";
var enemySprite = "images/EnemyCruiser01.png";
var enemySprite2 = "images/EnemyCruiser02.png";
var enemySprite3 = "images/EnemyCruiser03.png";
var enemySprite4 = "images/EnemyCruiser04.png";
var obstacleSprite = ["images/Civi02.png","images/Civi03.png","images/Civi04.png","images/Civi05.png"];
var bill1Sprite = "images/Billboard1.png"; var bill2Sprite = "images/Billboard2.png";
var bill3Sprite = "images/Billboard3.png"; var bill4Sprite = "images/Billboard4.png";
var bill5Sprite = "images/Billboard5.png"; var bill6Sprite = "images/Billboard6.png";
var bill7Sprite = "images/Billboard7.png"; var bill8Sprite = "images/Billboard8.png";
var sign1Sprite = "images/Sign1.png"; var sign2aSprite = "images/Sign2a.png"; var sign2bSprite = "images/Sign2b.png";
var sign3Sprite = "images/Sign3.png"; var sign4Sprite = "images/Sign4.png"; var sign5Sprite = "images/Sign5.png";
var checkpointSprite = "images/savePoint.png";
var logoSprite = "images/Logo2.png";

var titleImage = new Image(); titleImage.src = "images/Title.png";      titleImage.crossOrigin = "anonymous";
var winImage = new Image();     winImage.src = "images/Victory.png";      winImage.crossOrigin = "anonymous";
var failImage = new Image();   failImage.src = "images/Defeat.png";      failImage.crossOrigin = "anonymous";
var tut1Image = new Image();   tut1Image.src = "images/TutorialP1.png";  tut1Image.crossOrigin = "anonymous";
var tut2Image = new Image();   tut2Image.src = "images/TutorialP2.png";  tut2Image.crossOrigin = "anonymous";
var bgImage = titleImage;
var styleColor = "255, 215, 0";
var styleCounter;
var styleDirection;

//The canvas object
var canvas;
var CANVAS_W = 600;
var CANVAS_H = 600;
var canvasdata;
var gameLoop;
var frametime = FRAMETIME;

//Menu constants
var DIFF_MENU =     {opt: ["Easy", "Medium", "Hard"],
					 len: 3, width: 360, height: 60, x: CANVAS_W/2, y: CANVAS_H/2, sep: 100}; DIFF_MENU.x -= DIFF_MENU.width/2; DIFF_MENU.y -= DIFF_MENU.height/2;
var PAUSE_MENU =    {opt: ["Resume", "Restart from Beginning", "Restart from Checkpoint"],
					 len: 3, width: 360, height: 60, x: CANVAS_W/2, y: CANVAS_H/2, sep: 100}; PAUSE_MENU.x -= PAUSE_MENU.width/2; PAUSE_MENU.y -= PAUSE_MENU.height/2;
var DEFEAT_MENU =   {opt: ["Restart", "Change Difficulty", "Restart from Checkpoint"],
					 len: 3, width: 360, height: 60, x: CANVAS_W/2, y: CANVAS_H/2, sep: 100}; DEFEAT_MENU.x -= DEFEAT_MENU.width/2; DEFEAT_MENU.y -= DEFEAT_MENU.height/2;
var TUTORIAL_MENU = {opt: ["Continue"],
					 len: 1, width: 360, height: 60, x: CANVAS_W/2, y: CANVAS_H/2+260, sep: 100}; TUTORIAL_MENU.x -= TUTORIAL_MENU.width/2; TUTORIAL_MENU.y -= TUTORIAL_MENU.height/2;
var START_MENU =    {opt: ["Start", "Tutorial"],
					 len: 2, width: 360, height: 60, x: CANVAS_W/2, y: CANVAS_H/2+50, sep: 100}; START_MENU.x -= START_MENU.width/2; START_MENU.y -= START_MENU.height/2;
//Sound variables
var audio = new Audio('KillingTime.mp3')
audio.play();
audio.pause();
audio.loop = true;
//Menu variables
var menu = true;             //any menu
var startMenu = true;        //start screen
var tutMenu = false;         //tutorial menu
var tut1 = false;            //which tutorial screen
var diffMenu = false;        //difficulty menu
var failMenu = false;        //defeat menu
var pauseMenu = false;       //can the game be resumed
var menuSelection = 0;
var menuOptions = START_MENU;
var difficulty = 1;
var paused = false;          //paused but not menu screen
var mouseX = 0;              //current mouse position
var mouseY = 0;

//Data for handling the game
var obstacles;
var enemies;
var scenery;
var checkpoints = [];
var guard;
var ctx;
var player;
var boss;
var ctxOffsetX = 0;
var ctxOffsetY = 0;
var ctxOffsetX2 = 0;
var ctxOffsetY2 = 0;
var hasStarted = false;
var victory = false;
var defeat = false;

//Data for handling loading the game from a save state
var saveStateObstacles = [];
var saveStateEnemies = [];
var saveStatePlayer = [];
var saveStateCheckpoints = [];
var saveStateScenery = [];
var hasSavedState = false;


//Fires when the document has finished loading and begins
//Executing the game
$(document).ready(function(){
	canvas = $("#canvas")[0];
	ctx = canvas.getContext("2d");
	init(false);

	$(window).load(function() {
		draw();
	
		ctx.fillStyle = "rgba(0, 0, 0, 0.4)";
		ctx.fillRect(player.pos.x-CANVAS_W/2+player.width/2, player.pos.y-CANVAS_H/2+player.height/2, CANVAS_W, CANVAS_H);
		ctx.drawImage(titleImage, player.pos.x-CANVAS_W/2+player.width/2, player.pos.y-CANVAS_H/2+player.height/2);
		canvasdata = ctx.getImageData(0, 0, CANVAS_W, CANVAS_H);
		menu = true;
		startMenu = true;
		menuOptions = START_MENU;
		menuSelection = 0;
		styleCounter = 0.2;
		styleDirection = true;
		if(typeof game_loop != "undefined") clearInterval(game_loop);
		game_loop = setInterval(updatePauseMenu, frametime);
	});
});

//Initializes the game
function init(load){
	if (!load && hasSavedState) {
		ctx.translate(ctxOffsetX2, ctxOffsetY2);
		Orbit_createOrbits();
		obstacles = [];
		enemies = [];
		scenery = [];
		checkpoints = [];
		//Adds the player to the game
		player = new Entity(0, ORBIT_COUNT-1, 1, 98, 60, playerSprite);
		addPlayerProperties();
		//Creates all the obstacles on the map
		Obstacles_createObstacles();
		ctxOffsetX2 = 0; ctxOffsetY2 = 0;
		hasSavedState = false;
	} else if (load && hasSavedState) {
		loadState();
	} else {
		Orbit_createOrbits();
		obstacles = [];
		enemies = [];
		scenery = [];
		checkpoints = [];
		//Adds the player to the game
		player = new Entity(0, ORBIT_COUNT-1, 1, 98, 60, playerSprite);
		addPlayerProperties();
		//Creates all the obstacles on the map
		Obstacles_createObstacles();
		if(hasStarted){
			ctx.translate(ctxOffsetX, ctxOffsetY);
			ctxOffsetX2 -= ctxOffsetX; ctxOffsetY2 -= ctxOffsetY;
		}else{
			ctx.translate(	(-1)*player.pos.x + CANVAS_W/2 - player.width/2,
							(-1)*player.pos.y + CANVAS_H/2 - player.height/2);
		}
	}

	ctxOffsetX = 0; ctxOffsetY = 0;
	
	Background_generateStarfield();
	trimOverlap();
	hasStarted = true;
	paused = false;
	gameLoop = document.getElementById('gameLoop');
	audio.play();
	//gameLoop.play();
}

//Updates all elements in the game one step, and handles
//Their resulting states
function update(){
	if (!paused) {
		player.updatePlayer();
		boss.updatePosition();
		po = player.orbit;
		for(var i = 0; i < obstacles.length; i++){
			obstacles[i].updatePosition();
			if(obstacles[i].orbit - po > 10){
				obstacles.splice(i, 1);
			}
		}
		for(var i = 0; i < enemies.length; i++){
			enemies[i].updatePosition();
		}
		for(var i = 0; i < checkpoints.length; i++){
			checkpoints[i].updatePosition();
		}
		for(var i = 0; i < scenery.length; i++){
			scenery[i].updatePosition();
		}
		
		//Checks for collision between player object and obstacle objects
		if(EXPLORE_MODE != true){
			if(player.checkCollision(boss)){
				victory = true;
				menuMode();
			}
			for(var i = 0; i < obstacles.length; i++){
				if(player.checkCollision(obstacles[i])){
					defeat = true;
					menuMode();
				}
			}
			for(var i = 0; i < enemies.length; i++){
				if(enemies[i].checkDetection(player) || player.checkCollision(enemies[i])){
					defeat = true;
					menuMode();
				}
			}
			checkCheckpoints();
		}
		
		draw();
	}
}

//Draws all objects in the game onto the canvas
function draw(){
	Background_draw();
	Orbit_drawOrbits();
	
	boss.drawEntity();
	for(var i = 0; i < scenery.length; i++){
		scenery[i].drawEntity();
	}
	for(var i = 0; i < obstacles.length; i++){
		if(obstacles[i].direction < 0){
			obstacles[i].drawEntity(Math.PI);
		}else{
			obstacles[i].drawEntity(0);
		}
		
	}
	for(var i = 0; i < enemies.length; i++){
		enemies[i].drawGuard();
	}
	for(var i = 0; i < checkpoints.length; i++){
		checkpoints[i].drawEntity();
	}
	player.drawPlayer();
}

function checkCheckpoints(){
	var px = player.pos.x; var py = player.pos.y; var po = player.orbit;
	var pdist = Orbit_getPlanetDistance(px, py);
	for(var i = 0; i < checkpoints.length; i++){
		if(player.checkCollision(checkpoints[i])){
			saveState(i);
			break;
		}
		var cdist = Orbit_getPlanetDistance(checkpoints[i].pos.x, checkpoints[i].pos.y);
		if(Math.abs(pdist - cdist) < 50){
			if( (Math.abs(px - checkpoints[i].pos.x) < 200) && (Math.abs(py - checkpoints[i].pos.y) < 200)){
				saveState(i);
				break;
			}
		}
	}
}

function updatePauseMenu(){
	if (styleDirection) styleCounter += 0.007;
	else styleCounter -= 0.007;
	if (styleCounter >= 0.9 || styleCounter <= 0.1) styleDirection = !styleDirection;

	drawPauseMenu();
}

function drawPauseMenu(){
	ctx.putImageData(canvasdata, 0, 0);
	
	var length = menuOptions.len;
	var separation = menuOptions.sep;
	var rectWidth = menuOptions.width;
	var rectHeight = menuOptions.height;
	var rectX = menuOptions.x;
	var rectY = menuOptions.y;
	var style = "rgba(" + styleColor + ", " + styleCounter + ")"; //rectangle color
	
	//draw rectangle;
	ctx.fillStyle = "rgba(0, 0, 0, 0.6)";
	ctx.fillRect(player.pos.x+player.width/2-CANVAS_W/2+rectX, player.pos.y+player.height/2-CANVAS_H/2+rectY-10+menuSelection*separation, rectWidth, rectHeight);
	ctx.strokeStyle = style;
	ctx.lineWidth = 6;
	ctx.strokeRect(player.pos.x+player.width/2-rectWidth/2, player.pos.y+player.height/2-CANVAS_H/2+rectY-10+menuSelection*separation, rectWidth, rectHeight);

	//draw text	
	ctx.textAlign = "center";
	ctx.font = "20pt Arial";
	ctx.fillStyle = "Red";
	for (var i = 0; i < length; i++) {
		ctx.fillText(menuOptions.opt[i], player.pos.x+player.width/2-CANVAS_W/2+rectX+rectWidth/2, player.pos.y+player.height/2-CANVAS_H/2+rectY+rectHeight/2+separation*i);
	}
}

//Handles the change from game mode to menu mode
function menuMode(){
	menu = true;
	styleCounter = 0.12;
	styleDirection = true;
	
	if (victory) {
		changeBgImage(winImage);
		diffMenu = true;
		victory = false;
		menuSelection = 1;
		menuOptions = DIFF_MENU;
	} else if (defeat) {
		changeBgImage(failImage);
		diffMenu = false;
		failMenu = true;
		defeat = false;
		menuSelection = 2;
		menuOptions = DEFEAT_MENU;
	} else {
		changeBgImage(titleImage);
		menuSelection = 0;
	}

	if(typeof game_loop != "undefined") clearInterval(game_loop);
	game_loop = setInterval(updatePauseMenu, frametime);
}

//Starts the game again when menus are closed
function gameMode(){
	menu = false;
	if(typeof game_loop != "undefined") clearInterval(game_loop);
	game_loop = setInterval(update, frametime);
}

//Handles changes between menus as well as back to game mode
function menuOptionSelected(){
	if (failMenu) {
		failMenu = false;
		pauseMenu = false;
		
		if (menuSelection == 0) {
			menuOptions = PAUSE_MENU;
			init(false);
			gameMode();
		} else if (menuSelection == 1) {
			diffMenu = true;
			menuOptions = DIFF_MENU;
		} else {
			menuOptions = PAUSE_MENU;
			init(true);
			gameMode();
		}
		
	} else if (diffMenu) {
		difficulty = menuSelection;
		menuOptions = PAUSE_MENU;
		diffMenu = false;
		init(false);
		gameMode();
		
	} else if (startMenu) {
		startMenu = false;
		
		if (menuSelection == 0) {
			diffMenu = true;
			menuSelection = 1;
			menuOptions = DIFF_MENU;
		} else {
			tutMenu = true;
			tut1 = true;
			menuOptions = TUTORIAL_MENU;
			draw();
			changeBgImage(tut1Image);
			menuSelection = 0;
		}
		
	} else if (tutMenu) {
		if (tut1) {
			tut1 = false;
			draw();
			changeBgImage(tut2Image);
		} else {
			tutMenu = false;
			startMenu = true;
			draw();
			changeBgImage(titleImage);
			menuOptions = START_MENU;
		}

	  //initial pause menu
	} else if (menuSelection == 0) {
		pauseMenu = false;
		gameMode();
	} else if (menuSelection == 1) {
		pauseMenu = false;
		diffMenu = true;
		menuOptions = DIFF_MENU;
	} else {
		pauseMenu = false;
		init(true);
		gameMode();
	}
}

//Saves the current state of the map to the saveState arrays, and removes
//the checkpoint that caused the state to be saved (passed in as a parameter).
function saveState(point){
	saveStateObstacles = [];
	saveStateEnemies = [];
	saveStateScenery = [];
	saveStatecheckpoints = [];
	for(var i = 0; i < obstacles.length; i++){
		saveStateObstacles.push($.extend(true, {}, obstacles[i]));
	}
	for(var i = 0; i < enemies.length; i++){
		saveStateEnemies.push($.extend(true, {}, enemies[i]));
	}
	for(var i = 0; i < scenery.length; i++){
		saveStateScenery.push($.extend(true, {}, scenery[i]));
	}
	saveStatePlayer = $.extend(true, {}, player);
	checkpoints.splice(point, 1);
	for(var i = 0; i < checkpoints.length; i++){
		saveStateCheckpoints.push($.extend(true, {}, checkpoints[i]));
	}
	ctxOffsetX = 0; ctxOffsetY = 0;
	hasSavedState = true;
}

//Loads the state from the saveState arrays into the normal game arrays.
function loadState(){
	obstacles = []; enemies = []; scenery = []; checkpoints = [];
	for(var i = 0; i < saveStateObstacles.length; i++){
		obstacles.push($.extend(true, {}, saveStateObstacles[i]));
	}
	for(var i = 0; i < saveStateEnemies.length; i++){
		enemies.push($.extend(true, {}, saveStateEnemies[i]));
	}
	for(var i = 0; i < saveStateScenery.length; i++){
		scenery.push($.extend(true, {}, saveStateScenery[i]));
	}
	for(var i = 0; i < saveStateCheckpoints.length; i++){
		checkpoints.push($.extend(true, {}, saveStateCheckpoints[i]));
	}
	player = $.extend(true, {}, saveStatePlayer);
	ctx.translate(ctxOffsetX, ctxOffsetY);
	ctxOffsetX2 -= ctxOffsetX;
	ctxOffsetY2 -= ctxOffsetY;
	ctxOffsetX = 0; ctxOffsetY = 0;
}

function changeBgImage(image){
	ctx.fillStyle = "rgba(0, 0, 0, 0.4)";
	ctx.fillRect(player.pos.x-CANVAS_W/2+player.width/2, player.pos.y-CANVAS_H/2+player.height/2, CANVAS_W, CANVAS_H);
	bgImage = image;
	
	ctx.drawImage(bgImage, player.pos.x-CANVAS_W/2+player.width/2, player.pos.y-CANVAS_H/2+player.height/2);
	canvasdata = ctx.getImageData(0, 0, CANVAS_W, CANVAS_H);
}


$(document).bind("keyup", "down", function(){
	if (menu) {
		if (menuSelection <= 0) menuSelection = menuOptions.len-1;
		else menuSelection--;
	}
});
$(document).bind("keyup", "s", function(){
	if (menu) {
		if (menuSelection <= 0) menuSelection = menuOptions.len-1;
		else menuSelection--;
	}
});

$(document).bind("keyup", "up", function(){
	if (menu) {
		if (menuSelection >= menuOptions.len-1) menuSelection = 0;
		else menuSelection++;
	}
});
$(document).bind("keyup", "w", function(){
	if (menu) {
		if (menuSelection >= menuOptions.len-1) menuSelection = 0;
		else menuSelection++;
	}
});


$(document).bind("keydown", "down", function(){
	if (!menu) {
		if(player != undefined){player.playerDown();}
	}
});
$(document).bind("keydown", "s", function(){
	if (!menu) {
		if(player != undefined){player.playerDown();}
	}
});

$(document).bind("keydown", "up", function(){
	if (!menu) {
		if(player != undefined){player.playerUp();}
	}
});
$(document).bind("keydown", "w", function(){
	if (!menu) {
		if(player != undefined){player.playerUp();}
	}
});

$(document).bind("keydown", "left", function(){
	if (!menu) {
		if(player != undefined){player.playerLeft();}
	}
});
$(document).bind("keydown", "a", function(){
	if (!menu) {
		if(player != undefined){player.playerLeft();}
	}
});

$(document).bind("keydown", "right", function(){
	if (!menu) {
		if(player != undefined){player.playerRight();}
	}
});
$(document).bind("keydown", "d", function(){
	if (!menu) {
		if(player != undefined){player.playerRight();}
	}
});

$(document).bind("keydown", "space", function(){
	if (!menu) {
		if(player != undefined){player.playerSpace();}
	}
});

$(document).bind("keyup", "esc", function(){
	if (!menu) {
		pauseMenu = true;
		menuMode();
	} else if (pauseMenu) {
		pauseMenu = false;
		gameMode();
	}
});

$(document).bind("keypress", "return", function(){
	if (menu) {
		menuOptionSelected();
	} else {
		paused = !paused;
		
		ctx.textAlign = "left";
		ctx.font = "6pt Arial";
		ctx.fillStyle = "blue";
		ctx.fillText("Paused", player.pos.x+player.width/2-CANVAS_W/2+4, player.pos.y+player.height/2+CANVAS_H/2-6);
	}
});


$("#canvas").mousemove(function(e){
	if (menu) {
		var length = menuOptions.len;
		var separation = menuOptions.sep;
		var rectWidth = menuOptions.width;
		var rectHeight = menuOptions.height;
		var rectX = menuOptions.x;
		var rectY = menuOptions.y;
		var lineWidth = 6;
		var done = false;
		
		mouseX = e.offsetX;
		mouseY = e.offsetY;

		if (mouseX === undefined) { //firefox sucks
			mouseX = e.originalEvent.layerX;
			mouseY = e.originalEvent.layerY;
		}
		
		if (mouseX >= rectX && mouseX <= rectX+rectWidth) {
			for (var i = 0; i < length && !done; i++) {
				if (mouseY >= rectY-lineWidth*2+separation*i && mouseY <= rectY+rectHeight-lineWidth+separation*i) {
					styleColor = "0, 255, 50";
					menuSelection = i;
					done = true;
				}
			}
		}
		
		if (!done) styleColor = "255, 215, 0";
	}
});

$("#canvas").click(function(e){
	if (menu) {
		var length = menuOptions.len;
		var separation = menuOptions.sep;
		var rectWidth = menuOptions.width;
		var rectHeight = menuOptions.height;
		var rectX = menuOptions.x;
		var rectY = menuOptions.y;
		var lineWidth = 6;
		var done = false;
		
		if (mouseX >= rectX && mouseX <= rectX+rectWidth) {
			for (var i = 0; i < length && !done; i++) {
				if (mouseY >= rectY-lineWidth*2+separation*i && mouseY <= rectY+rectHeight-lineWidth+separation*i) {
					styleColor = "255, 215, 0";
					menuSelection = i;
					done = true;
					menuOptionSelected();
				}
			}
		}
	}
});



